
#include <set>
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/algorithm/string.hpp>
#include <zen/defines.hpp>
#include <JSL.hpp>

#include "ShaderManager.hpp"

#include "model/Definition.hpp"

#include "Model.hpp"

namespace zen {

	namespace video {


		Model::Model(model::PDefinition definition) {
			this->definition = definition;
			model::Definition* modelDefinition = definition.get();
			boneCount = modelDefinition->getBoneCount();
			bones = new model::Bone*[boneCount];
			for (glm::uint i = 0; i < boneCount; i++) {
				bones[i] = new model::Bone(*modelDefinition->getBones()[i]);
			}
		}

		Model::Model(const Model &other) {
			if (bones != nullptr) {
				for (glm::uint i = 0; i < boneCount; i++)
					delete bones[i];
				delete[] bones;
			}
			*this = other;
		}

		Model::~Model() {
			if (bones != nullptr) {
				for (glm::uint i = 0; i < boneCount; i++)
					delete bones[i];
				delete[] bones;
			}
		}

		Model& Model::operator = (const Model &other) {
			definition = other.definition;
			boneCount = other.boneCount;
			bones = new model::Bone*[boneCount];
			for (glm::uint i = 0; i < boneCount; i++)
				bones[i] = new model::Bone(*other.bones[i]);
			return *this;
		}

		void Model::setAllBonesAnimationFrame(glm::uint start, glm::uint end, glm::uint position, model::AnimType type, glm::float32 speed) {
			model::Animation** animations = (*definition).getAnimations();
			for (glm::uint i = 0; i < boneCount; i++)
				bones[i]->setAnimationFrame(animations, start, end, position, type, speed);
		}

		void Model::setBoneAnimationFrame(glm::uint boneIndex, glm::uint start, glm::uint end, glm::uint position, model::AnimType type, glm::float32 speed) {
			model::Animation** animations = (*definition).getAnimations();
			if (boneIndex < boneCount)
				bones[boneIndex]->setAnimationFrame(animations, start, end, position, type, speed);
		}

		void Model::update(int interval) {
			if (bones != NULL) {
				model::Animation** animations = (*definition).getAnimations();
				for (glm::uint i = 0; i < boneCount; i++)
					bones[i]->update(interval, bones, animations);
			}
		}

		void Model::draw() const {
			glPushMatrix();
			ShaderManager* materialShaderManager = (*definition).getMaterialShaderManager();
			model::Mesh** meshes = (*definition).getMeshes();
			Material* materials = (*definition).getMatrerials();
			for (glm::uint i = 0; i < boneCount; i++)
				bones[i]->draw(view, materialShaderManager, meshes, materials);
			glPopMatrix();
			glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
			glBindVertexArray(0);
		}


	} // namespace video

} // namespace zen
